package com.zmm.framework.biz.operationlog.aspect;

import com.zmm.framework.common.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: 福禄寿
 * @Date: 2024/9/5 下午5:23
 * @Des: xiaohashu
 **/
@Aspect
@Slf4j
public class ApiOperationLogAspect {

    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.zmm.framework.biz.operationlog.aspect.ApiOperationLog)")
    public void apiOperationLog() {}

    /**
     * 环绕通知
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        //请求开始时间
        long startTime = System.currentTimeMillis();

        //获取被请求的类和方法
        String className = point.getTarget().getClass().getName();
        String methodName = point.getSignature().getName();

        //请求入参
        Object[] args = point.getArgs();

        //入参转JSON字符串
        String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(","));
        //功能描述信息
        String description = getApiOperationLogDescription(point);
        // 打印请求相关参数
        log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",
                description, argsJsonStr, className, methodName);

        //执行切点方法
        Object result = point.proceed();
        //执行耗时
        long executionTime = System.currentTimeMillis() - startTime;

        // 打印出参等相关信息
        log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ",
                description, executionTime, JsonUtils.toJsonString(result));
        return result;
    }

    /**
     * 获取注解的描述信息
     * @return
     */
    private String getApiOperationLogDescription(ProceedingJoinPoint point){
        //从ProceedingJoinPoint获取MethodSignature的方法
        MethodSignature signature = (MethodSignature) point.getSignature();
        //从MethodSignature获取方法
        Method method = signature.getMethod();
        //从方法获取LogExecution注解
        ApiOperationLog annotation = method.getAnnotation(ApiOperationLog.class);
        //获取注解的描述信息
        return annotation.description();
    }

    private Function<Object,String> toJsonStr(){
        return JsonUtils::toJsonString;
    }


}
